<?php

declare(strict_types=1);

namespace App\Repositories\Gashapon;

use App\Exceptions\BasicException;
use App\Models\MainDB\AccountLog;
use App\Models\MainDB\User as MainUserModel;
use App\Models\MainDB\Gashapon\User as Model;
use App\Models\MainDB\Gashapon\BalanceLog as BalanceLogModel;
use App\Traits\Singleton;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\DB;

class UserRepository
{
    use Singleton;

    public function checkNextLevelExp(int $level, int $exp)
    {
        $nextLevel = LevelRepository::getInstance()->next($level);
        if (!$nextLevel || $nextLevel->exp > $exp) {
            return $level;
        }
        return $nextLevel->level;
    }

    public function drawUpdate(int $userId, int $input, int $output, int $count)
    {
        // 用户今日数据
        $date         = Carbon::now()->toDateString();
        $userStatDate = UserStatDateRepository::getInstance()->one(['user_id' => $userId, 'date' => $date], false, true);
        if (!$userStatDate) {
            UserStatDateRepository::getInstance()->create(['user_id' => $userId, 'date' => $date, 'input' => $input, 'output' => $output, 'count' => $count]);
        } else {
            $userStatDate->input  += $input;
            $userStatDate->output += $output;
            $userStatDate->count  += $count;
            $userStatDate->save();
        }
        // 用户本周数据
        $week         = Carbon::now()->year . Carbon::now()->weekOfYear;
        $userStatWeek = UserStatWeekRepository::getInstance()->one(['user_id' => $userId, 'week' => $week], false, true);
        if (!$userStatWeek) {
            UserStatWeekRepository::getInstance()->create(['user_id' => $userId, 'week' => $week, 'input' => $input, 'output' => $output, 'count' => $count]);
        } else {
            $userStatWeek->input  += $input;
            $userStatWeek->output += $output;
            $userStatWeek->count  += $count;
            $userStatWeek->save();
        }
    }

    // 抽奖用户
    public function drawUser($setting, int $userId, bool $lock = false)
    {
        $query = Model::query();
        $query = $query->where('id', $userId);
        $query->with(['week' => function ($with) {
            $with->where('week', '=', Carbon::now()->year . Carbon::now()->weekOfYear);
        }, 'date'            => function ($with) {
            $with->where('date', '=', Carbon::now()->format("Y-m-d"));
        }]);
        if ($lock) {
            $query->lockForUpdate();
        }
        $model = $query->first();
        if (!$model) {
            throw new BasicException(-1, '用户余额不足');
        }
        $model->game              = Collection::make([]);
        $model->game->output_rate = $model->output == 0 ? 0 : $model->input / $model->output;
        $model->game->is_novice   = $this->isNovice($setting, $model);
        $model->game->weight      = $this->weight($model); // 权重
        return $model;
    }

    // 是否新手
    protected function isNovice($setting, $user)
    {
        $novice = true;
        // 用户数量 > 设置新手数量 && ()
        if ($user->count > $setting->novice_count && ($user->game->output_rate > $setting->novice_min_output_rate || $user->game->output_rate < $setting->novice_max_output_rate)) {
            $novice = false;
        }
        return $novice;
    }

    // 权重
    protected function weight($user)
    {
        $weight         = 0;
        $userCount      = $user->week->count ?? 0;
        $userInput      = $user->week->input ?? 0;
        $userOutput     = $user->week->output ?? 0;
        $userOutputRate = ($userOutput == 0 || $userInput == 0) ? 0 : $userOutput / $userInput * 100;

        if ($userCount > 0) {
            $settings = WeightSettingRepository::getInstance()->get();
            if ($settings->isNotEmpty()) { // 用户抽奖数量 >= 设置数量 &&  用户产出比 >= 设置产出比
                $settings->where('count', '<=', $userCount)->sortByDesc('weight')->each(function ($item) use ($userOutputRate, &$weight) {
                    if ($weight == 0 && $userOutputRate >= $item->output_rate) {
                        $weight = $item->weight;
                    }
                });
            }
        }
        return $weight;
    }

    public function all(array $filters = [], int $page = 1, int $perPage = 15)
    {
        $query = Model::query();
        $query->where($filters);
        $models = $query->paginate($perPage, ['*'], 'page', $page);
        return $models;
    }

    public function one(array $filters, bool $fail = false)
    {
        $query = Model::query();
        $query->where($filters);
        $model = $fail ? $query->firstOrFail() : $query->first();
        return $model;
    }

    public function find(int $id)
    {
        $model = $this->one(['id' => $id], true);
        return $model;
    }

    public function create(array $data)
    {
        $model = new Model();
        $model->fill($data);
        $model->save();
        return $model;
    }

    public function update(int $id, array $data)
    {
        $model = $this->find($id);
        $model->fill($data);
        $model->save();
        return $model;
    }

    public function info(int $userId)
    {
        $query = MainUserModel::query();
        $query->where('user_id', $userId);
        $query->with(['gashapon']);
        $info = $query->first();
        if ($info->gashapon) {
            $nextLevel                 = LevelRepository::getInstance()->next($info->gashapon->level);
            $info->gashapon->nextLevel = $nextLevel->level ?? $info->gashapon->level;
            $info->gashapon->nextExp   = $nextLevel->exp ?? $info->gashapon->exp;
        }
        return $info;
    }

    public function swap(int $userId, int $count)
    {
        DB::beginTransaction();
        try {
            $setting = SettingRepository::getInstance()->one([]); // 游戏配置
            if (!$setting || !$setting->is_open) {
                throw new BasicException('游戏未开启');
            }
            $coin = $count * $setting->balance_coin;
            $this->decUserMoney($userId, $coin);
            app('model_account_log')->addLog($userId, $coin, "兑换游戏道具x{$count}", 224);

            $user = Model::query()->where('id', $userId)->lockForUpdate()->first();
            if (!$user) {
                $user = UserRepository::getInstance()->create(['id' => $userId, 'balance' => $count, 'total_balance' => $count]);
            } else {
                $user->balance       += $count;
                $user->total_balance += $count;
                $user->save();
            }
            BalanceLogRepository::getInstance()->swap($userId, $count, $user->balance);
            DB::commit();
        } catch (\Exception $exception) {
            DB::rollBack();
            throw new BasicException(-1, '兑换失败' . $exception->getMessage());
        }
        return $user;
    }

    public function decUserMoney(int $userId, int $coin)
    {
        $mainUser = MainUserModel::where('user_id', $userId)->lockForUpdate()->firstOrFail();
        if ($mainUser->money < $coin) {
            throw new BasicException(-1, '用户金币不足');
        }
        $mainUser->money -= $coin;
        $mainUser->save();
    }


}
